/*
 * lock.h
 *
 *  Created on: Nov 30, 2011
 *      Author: lin
 */

#ifndef CONCURRENT_H_
#define CONCURRENT_H_
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <pthread.h>
#include <sys/types.h>
#include <bits/pthreadtypes.h>
#include <semaphore.h>
#include <unistd.h>
#include <errno.h>

#include "def/defs.h"
#include "zmalloc/zmalloc.h"

#define _pthread_call(label,no) \
    do{\
        int _callno = (no);\
        if(_callno!=0){\
            fatal_no(label,_callno);\
        }\
    }while(0)

//pthread_key
#define thread_key pthread_key_t
#define thread_key_create(t_key,destr_fn) _pthread_call("create pthread_key",pthread_key_create(t_key, destr_fn))
#define thread_key_delete(t_key) _pthread("delete pthread_key",pthread_key_delete(t_key))
#define thread_key_set(t_key,val) _phread("pthread_key set",pthread_setspecific(t_key,val))
#define thread_key_get(t_key)  pthread_getspecific(t_key)
//lock
#define mutex pthread_mutex_t
#define mutex_init(lock)   _pthread_call("init pthread_mutex",pthread_mutex_init(lock, NULL))
#define mutex_lock(lock)   _pthread_call("lock pthread_mutex",pthread_mutex_lock(lock))
#define mutex_trylock(lock)  pthread_mutex_trylock(lock)
#define mutex_unlock(lock) _pthread_call("unlock pthread_mutex",pthread_mutex_unlock(lock))
#define mutex_destory(lock) _pthread_call("destroy pthread_mutex",pthread_mutex_destroy(lock))

#define cond pthread_cond_t
#define cond_init(cond)  _pthread_call("init pthread_cond",pthread_cond_init(cond,NULL))
#define cond_wait(cond,lock)  _pthread_call("wait pthread_cond",pthread_cond_wait(cond,lock))
#define cond_single(cond)  _pthread_call("signal pthread_cond",pthread_cond_signal(cond))
#define cond_single_all(cond)  _pthread_call("broadcast pthread_cond",pthread_cond_broadcast(cond))

//quicklock,spin
#define spin pthread_spinlock_t
#define spin_init(lock)   _pthread_call("init pthread_spinlock",pthread_spin_init(lock, 0))
#define spin_lock(lock)   _pthread_call("lock pthread_spinlock",pthread_spin_lock(lock))
#define spin_trylock(lock)  pthread_spin_trylock(lock)
#define spin_unlock(lock) _pthread_call("unlock pthread_spinlock",pthread_spin_unlock(lock))
#define spin_destory(lock) _pthread_call("destroy pthread_spinlock",pthread_spin_destroy(lock))
//rwlock,pthread
#define rwlock pthread_rwlock_t
#define rwlock_initializer PTHREAD_RWLOCK_INITIALIZER
#define rwlock_init(lock) _pthread_call("init pthread_rwlock",pthread_rwlock_init(lock,NULL))

#define rwlock_unlock(lock) _pthread_call("unlock pthread_rwlock",pthread_rwlock_unlock(lock))
#define rwlock_destory(lock) _pthread_call("destroy pthread_rwlock",pthread_rwlock_destroy(lock))
//rdlock
#define rwlock_rdlock(lock) _pthread_call("rdlock pthread_rwlock",pthread_rwlock_rdlock(lock))
#define rwlock_tryrdlock(lock) pthread_rwlock_tryrdlock((lock))
//wrlock
#define rwlock_wrlock(lock) _pthread_call("wrlock pthread_rwlock",pthread_rwlock_wrlock(lock))
#define rwlock_tryrwlock(lock) pthread_rwlock_trywrlock((lock))

//atomic
#define atomic_get(x)  __sync_val_compare_and_swap((x),0,0)
#define atomic_set(x,y) __sync_lock_test_and_set ((x),(y))

#define atomic_inc_get(x) __sync_add_and_fetch((x),1)
#define atomic_dec_get(x) __sync_sub_and_fetch((x),1)
#define atomic_add_get(x,y) __sync_add_and_fetch((x),(y))
#define atomic_sub_get(x,y) __sync_sub_and_fetch((x),(y))

#define atomoc_get_inc(x) __sync_fetch_and_add((x),1)
#define atomic_get_dec(x) __sync_fetch_and_sub((x),1)
#define atomic_get_add(x,y) __sync_fetch_and_add((x),(y))
#define atomic_get_sub(x,y) __sync_fetch_and_sub((x),(y))

#define atomic_bool_cas(x,oldval,newval) __sync_bool_compare_and_swap ((x) , (oldval), (newval))
#define atomic_val_cas(x,oldval,newval) __sync_val_compare_and_swap ((x) , (oldval), (newval))
#define mb_sync() __sync_synchronize()
//semaphore
typedef struct semaphore {
    unsigned int value;
    sem_t sem;
} semaphore_t;

#define _sem_call(label,no)\
    do{\
        int _no=(no);\
        if(_no==-1){\
            _no=errno;\
            fatal_no(label,_no);\
        }\
    }while(0)\


#define semaphore_create(v)\
    do{\
        unsigned int _v = (v);\
        semaphore_t * s = zmalloc(sizeof(semaphore_t));\
        s->value = _v;\
        _sem_call("sem create",sem_init(&s->sem, 0, _v));\
        return s;\
    }while(0)

#define semaphore_destory(sem)\
    do{\
        semaphore_t *_sem = (sem);\
        _sem_call("sem destory",sem_destroy(&_sem->sem));\
        zfree();\
    }while(0)

#define semaphore_post(sem)\
    do{\
        semaphore_t *_sem = (sem);\
        _sem_call("sem post",sem_post(&_sem->sem));\
    }while(0)

#define semaphore_post_all(sem)\
    do{\
        unsigned int i = sem->value;\
        while(i-->0){\
            _sem_call("sem post",sem_post(&_sem->sem));\
        }\
    }while(0)

#define semaphore_wait(sem)\
    do{\
       semaphore_t *_sem = (sem);\
       while(sem_wait(&_sem->sem)==-1){\
           int err = errno;\
           if(err!=EINTR){\
               fatal("sem wait",err);\
               break;\
           }\
       }\
    }while(0)

#define semaphore_wait_all(sem)\
    do{\
        unsigned int i = sem->value;\
        while(i-->0){\
            _sem_call("sem wait",sem_wait(&_sem->sem));\
        }\
    }while(0)

#endif /* CONCURRENT_H_ */
